"""
@Author    : ghenyar
@Time      : 2025/9/29 17:17
@File      : db
@Desc      :  数据库会话管理
"""
import contextlib
from typing import Generator, AsyncGenerator

from fastapi import HTTPException
from sqlalchemy import create_engine
from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession, async_sessionmaker
from sqlalchemy.orm import sessionmaker, Session
from sqlalchemy.ext.declarative import declarative_base

from app.core.config import conf
from app.utils.log import LoggingUtil

logger = LoggingUtil(f"{__name__}.db")

config = conf.database

pool_options, connect_args = config.get_options()

# 同步数据库配置
sync_engine = create_engine(config.sync_url, **pool_options, connect_args=connect_args)
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=sync_engine)
Base = declarative_base()

# 异步数据库配置
async_engine = create_async_engine(config.async_url, **pool_options, connect_args=connect_args)
AsyncSessionLocal = async_sessionmaker(
    async_engine,
    class_=AsyncSession,
    expire_on_commit=False,
    autoflush=False,
    autocommit=False
)


class SyncDBSession:
    """同步数据库会话上下文管理器"""

    def __init__(self):
        self.db = SessionLocal()

    def __enter__(self) -> Session:
        return self.db

    def __exit__(self, exc_type, exc_value, traceback):
        self.db.close()


def get_db() -> Generator[Session, None, None]:
    """
    同步数据库会话依赖（用于FastAPI依赖注入）
    """
    with SyncDBSession() as db:
        try:
            yield db
        except Exception:
            db.rollback()
            raise
        finally:
            db.close()


@contextlib.contextmanager
def get_db_session() -> Generator[Session, None, None]:
    """
    上下文管理器方式获取数据库会话
    使用示例：
        with get_db_session() as db:
            user = db.query(User).first()
            # 自动提交和关闭
    """
    db = SessionLocal()
    try:
        yield db
        db.commit()
    except Exception as e:
        db.rollback()
        logger.error(f"数据库错误：{e}")
        raise HTTPException(status_code=500, detail="数据库操作失败")
    finally:
        db.close()


async def async_get_db() -> AsyncGenerator[AsyncSession, None]:
    """
    异步数据库会话依赖（推荐用于FastAPI）
    """
    async with AsyncSessionLocal() as db:
        try:
            yield db
        except Exception:
            await db.rollback()
            raise


@contextlib.asynccontextmanager
async def get_async_db_session() -> AsyncGenerator[AsyncSession, None]:
    """
    异步上下文管理器方式获取数据库会话
    """
    async with AsyncSessionLocal() as db:
        try:
            yield db
            await db.commit()
        except Exception as e:
            await db.rollback()
            logger.error(f"数据库错误：{e}")
            raise HTTPException(status_code=500, detail="数据库操作失败")
